package com.vpx.server.service.system.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vpx.server.bean.entity.SqlConfig;
import com.vpx.server.bean.info.system.SqlParam;
import com.vpx.server.framework.config.SpringUtils;
import com.vpx.server.mapper.system.SqlMapper;
import com.vpx.server.mapper.system.SysUserMapper;
import com.vpx.server.service.system.SqlService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.*;

@Service
public class SqlServiceImpl implements SqlService {
    @Autowired
    SqlMapper sqlMapper;

    public static final String REPORT_TYPE_KEY = "reportconfig_type";


    @Override
    public SqlConfig findSqlConfig(SqlParam param) {
        LambdaQueryWrapper<SqlConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CharSequenceUtil.isNotBlank(param.getId()), SqlConfig::getId, param.getId())
                .eq(CharSequenceUtil.isNotBlank(param.getType()), SqlConfig::getType, param.getType());
        return sqlMapper.selectOne(queryWrapper);
    }

    @Override
    public Page<Map<String, Object>> findByPage(String code, Map<String, Object> param) {
        if(param == null) {
            param = new HashMap<>();
        }
        param.put(REPORT_TYPE_KEY,code);

        //构建分页和排序参数
        long page = Long.parseLong(String.valueOf(param.getOrDefault("current", 1)));
        long pageSize = Long.parseLong(String.valueOf(param.getOrDefault("size", 10)));
        long offset = (page - 1) * pageSize;
        param.put("offset", offset);
        param.put("size", pageSize);
        String sortField = String.valueOf(param.getOrDefault("sortField", ""));
        String sortOrder = String.valueOf(param.getOrDefault("sortOrder", ""));
        param.put("sortField",sortField);
        param.put("sortOrder",sortOrder);
        Page<Map<String, Object>> pageObj = new Page<>(page, pageSize);
        SqlConfig config = this.findByKeyCode(code);
        long total = 0;
        List<Map<String,Object>> records = null;
        if(StringUtils.isBlank(config.getQueryPageSqlText())) {
            //不包含分页参数 采用系统默认分页
            total = Long.parseLong(String.valueOf(sqlMapper.executeQueryPageCount(param).getOrDefault("num","0")));
            records = this.sqlMapper.executeQueryPage(param);
        } else {
            //自定义分页
            Map<String,Object> result = this.sqlMapper.executeQueryPageSqlText(param);
            if(ObjectUtil.isNotEmpty(result)) {
                Set<String> keys = result.keySet();
                for (String key : keys) {
                    total = Convert.convert(Long.class,result.get(key));
                    break;
                }
            }
            records = this.sqlMapper.executeQuery(param);
        }
        pageObj.setTotal(total);
        pageObj.setRecords(records);
        invokeSqlBean(code,pageObj,Page.class);
        return pageObj;
    }

    @Override
    public Page<JSONObject> findPageObj(String code, Map<String, Object> param) {
        if(param == null) {
            param = new HashMap<>();
        }
        param.put(REPORT_TYPE_KEY,code);

        //构建分页和排序参数
        long page = Long.parseLong(String.valueOf(param.getOrDefault("current", 1)));
        long pageSize = Long.parseLong(String.valueOf(param.getOrDefault("size", 10)));
        long offset = (page - 1) * pageSize;
        param.put("offset", offset);
        param.put("size", pageSize);
        String sortField = String.valueOf(param.getOrDefault("sortField", ""));
        String sortOrder = String.valueOf(param.getOrDefault("sortOrder", ""));
        param.put("sortField",sortField);
        param.put("sortOrder",sortOrder);
        Page<JSONObject> pageObj = new Page<>(page, pageSize);
        SqlConfig config = this.findByKeyCode(code);
        long total = 0;
        List<Map<String,Object>> records = null;
        if(StringUtils.isBlank(config.getQueryPageSqlText())) {
            //不包含分页参数 采用系统默认分页
            total = Long.parseLong(String.valueOf(this.sqlMapper.executeQueryPageCount(param).getOrDefault("num","0")));
            records = this.sqlMapper.executeQueryPage(param);
        } else {
            //自定义分页
            Map<String,Object> result = this.sqlMapper.executeQueryPageSqlText(param);
            if(ObjectUtil.isNotEmpty(result)) {
                Set<String> keys = result.keySet();
                for (String key : keys) {
                    total = Convert.convert(Long.class,result.get(key));
                    break;
                }
            }
            records = this.sqlMapper.executeQuery(param);
        }
        List<JSONObject> recordList = new ArrayList<>();
        if(records != null && records.size() > 0) {
            records.forEach(record->{
                recordList.add(Convert.convert(JSONObject.class,record));
            });
        }
        pageObj.setTotal(total);
        pageObj.setRecords(recordList);
        invokeSqlBean(code,pageObj,Page.class);
        return pageObj;
    }

    @Override
    public List<Map<String, Object>> findListMap(String code,Map<String, Object> param) {
        if(param == null) {
            param = new HashMap<>();
        }
        param.put(REPORT_TYPE_KEY,code);
        List<Map<String, Object>> list = this.sqlMapper.executeQuery(param);
        invokeSqlBean(code,list,List.class);
        return list;
    }

    @Override
    public Map<String, Object> findOneMap(String code,Map<String, Object> param) {
        if(param == null) {
            param = new HashMap<>();
        }
        param.put(REPORT_TYPE_KEY,code);
        List<Map<String, Object>> list = this.sqlMapper.executeQuery(param);
        Map<String, Object> result = null;
        if(list != null && list.size() > 0) {
            result = list.get(0);
        }
        invokeSqlBean(code,list,List.class);
        return result;
    }

    @Override
    public <T> T findOne(String code, Map<String, Object> params, Class<T> resultType) {
//        Map<String,Object> result = this.findOneMap(code,params);
        if(params == null) {
            params = new HashMap<>();
        }
        params.put(REPORT_TYPE_KEY,code);
        List<Map<String, Object>> list = this.sqlMapper.executeQuery(params);
        Map<String, Object> result = null;
        if(list != null && list.size() > 0) {
            result = list.get(0);
        }
        T resultVal = null;
        if(ObjectUtil.isNotEmpty(result)) {
            Set<String> keys = result.keySet();
            for (String key : keys) {
                resultVal = Convert.convert(resultType,result.get(key));
                break;
            }
        }
        if(params.get("queryBySql") == null) {
            invokeSqlBean(code,resultVal,resultType);
        }
        return resultVal;
    }

    @Override
    public <T> List<T> findList(String code, Map<String, Object> params, Class<T> resultType) {
        List<T> resultVals = new ArrayList<>();
//        List<Map<String,Object>> result =  this.findListMap(code,params);
        if(params == null) {
            params = new HashMap<>();
        }
        params.put(REPORT_TYPE_KEY,code);
        List<Map<String, Object>> result = this.sqlMapper.executeQuery(params);

        if(ObjectUtil.isNotEmpty(result)) {
            //获取key
            Map<String,Object> resultMap = result.get(0);
            Set<String> keys = resultMap.keySet();
            String resultKey = "";
            for (String key : keys) {
                resultKey = key;
                break;
            }


            for(Map<String,Object> obj:result) {
                resultVals.add(Convert.convert(resultType,obj.get(resultKey)));
            }

        }
        if(params.get("queryBySql") == null) {
            invokeSqlBean(code,resultVals,List.class);
        }

        return resultVals;
    }

    @Override
    public <T> T findOneObject(String code, Map<String, Object> params, Class<T> resultType) {
//        Map<String,Object> result = this.findOneMap(code,params);

        if(params == null) {
            params = new HashMap<>();
        }
        params.put(REPORT_TYPE_KEY,code);
        List<Map<String, Object>> list = this.sqlMapper.executeQuery(params);
        Map<String, Object> result = null;
        if(list != null && list.size() > 0) {
            result = list.get(0);
        }

        T resultObj = null;
        if(result != null) {
            resultObj = Convert.convert(resultType,result);
        }
        if(params.get("queryBySql") == null) {
            invokeSqlBean(code,resultObj,resultType);
        }

        return resultObj;
    }

    @Override
    public <T> List<T> findListObject(String code,Map<String, Object> params, Class<T> resultType) {
        if(params == null) {
            params = new HashMap<>();
        }
        params.put(REPORT_TYPE_KEY,code);
        List<Map<String, Object>> results = this.sqlMapper.executeQuery(params);

        List<T> resultObjs = new ArrayList<>();
        if(results != null) {
            results.forEach(result->{
                resultObjs.add(Convert.convert(resultType,result));
            });
        }
        if(params.get("queryBySql") == null) {
            invokeSqlBean(code,resultObjs,List.class);
        }

        return resultObjs;
    }

    @Override
    public int execute(String code,Map<String, Object> param) {
        if(param == null) {
            param = new HashMap<>();
        } else {
            // huatianstandard:约定俗成，批量更新的集合参数名统一传入list时，若list为空则不执行
            if (param.containsKey("list")) {
                Object o = param.get("list");
                if (o == null) {
                    return 0;
                }
                if (o instanceof ArrayList) {
                    if (((ArrayList<?>) o).size() == 0) {
                        return 0;
                    }
                } else if (o instanceof JSONArray) {
                    if (((JSONArray) o).size() == 0) {
                        return 0;
                    }
                }
            }
        }
        param.put(REPORT_TYPE_KEY,code);
        int result = this.sqlMapper.executeOperator(param);
        invokeSqlBean(code,param,Map.class);
        return result;
    }

    @Override
    public int execute(String code) {
        return this.execute(code,null);
    }

    @Override
//    @Cacheable(cacheNames = AppCacheConstants.REPORT_CONFIG, key="#type", unless = "#result == null")
    public SqlConfig findByKeyCode(String code) {

        LambdaQueryWrapper<SqlConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SqlConfig::getKeyCode, code);
        SqlConfig config = this.sqlMapper.selectOne(queryWrapper);

        return config;
    }

    /**
     * 反射执行方法
     */
    public void invokeSqlBean(String key,Object param,Class<?>... parameterTypes) {
        SqlConfig config = findByKeyCode(key);

        if(StringUtils.isNotBlank(config.getBeanName()) && StringUtils.isNotBlank(config.getMethodName())) {
            String beanName = StrUtil.lowerFirst(config.getBeanName());
            Object bean = SpringUtils.getBean(beanName);
            try{
                Method method = bean.getClass().getMethod(config.getMethodName(),parameterTypes);
                Object result = method.invoke(bean,param);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public long getPageCount(String code,Map<String, Object> param) {
        if(param == null) {
            param = new HashMap<>();
        }
        param.put(REPORT_TYPE_KEY,code);
        return Long.parseLong(String.valueOf(this.sqlMapper.executeQueryPageCount(param).getOrDefault("num","0")));
    }

}
